import { fileUpload } from '@/types/file'
import { fileService } from '@/api/modules/file'

export default function useUploadFile() {
  const uploadFileInput = ref<any>(null)
  /**
   * 上传文件模型
   */
  const fileContainer = reactive({
    hash: '',
    name: '', // 文件名称
    file: {} as File, // 文件流
    data: [] as Array<fileUpload>, // 文件切片
    worker: {} as Worker,
  })
  /**
   * 切片大小(1mb) the chunk size
   */
  const chunkSize = ref(10 * 1024) // 10kb
  // const chunkSize = 10 * 1024 * 1024  //10MB

  // 生成hash文件的进度
  const hashPercentage = ref(0)

  /**
   * 选择文件
   * @param e
   */
  const handleFileChange = function (e: Event) {
    const [file] = e.target && (e.target as any).files
    if (!file) return
    // 在vue2中，使用Object.assign(this.$data, this.$options.data())重置data

    fileContainer.file = file
    fileContainer.name = file.name
  }

  /**
   * 初始化文件上传
   */
  const initFileContainer = function () {
    const form = document.getElementById('myform') as any
    form!.reset()

    // console.log('uploadFileInput', uploadFileInput.value.outerHTML)
    Object.assign(fileContainer, { file: null })
    fileContainer.data.splice(0, fileContainer.data.length) // 清空数组
    fileContainer.name = ''
    hashPercentage.value = 0
  }

  /**
   * 点击上传
   */
  const handleUpload = async function () {
    if (!fileContainer.file) return
    // 将文件切片，切片数量通过文件大小控制(默认：10mb)
    const fileChunkList = createFileChunk(fileContainer.file)

    // 计算生成hash值
    fileContainer.hash = (await calculateHash(fileChunkList)) as string

    // 验证是否已经上传
    // const { shouldUpload } = await fileService.verifyUploaded(
    //   fileContainer.file.name,
    //   fileContainer.hash
    // )
    // if (!shouldUpload) {
    //   ElMessage({
    //     message: 'skip upload：file upload success',
    //     type: 'success'
    //   })
    //   return
    // }

    fileContainer.data = fileChunkList.map(
      ({ file }, index) =>
        ({
          // 根据文件内容生成的hash值
          fileHash: fileContainer.hash + '-' + index,
          chunk: file,
          index,
          // 切片标识：（文件名 + 下标）
          hash: fileContainer.name + '-' + index,
          percentage: 0,
        }) as fileUpload,
    )
    await uploadChunks()
  }

  /**
   * 通过文件对象 -> 生成文件切片
   * @param file 文件对象 : file
   * @param size 分片大小（默认：10mb）
   */
  const createFileChunk = function (
    file: File,
    size: number = chunkSize.value,
  ) {
    const fileChunkList: { file: Blob }[] = []
    let cur = 0
    while (cur < file.size) {
      // 文件以size长度的进行切割存储到切片数组中
      const chunk = { file: file.slice(cur, cur + size) } as { file: Blob }
      fileChunkList.push(chunk)
      cur += size
    }
    return fileChunkList
  }

  /**
   * 上传切片
   */
  const uploadChunks = async function () {
    const requestList = fileContainer.data
      .map(({ chunk, fileHash, index }) => {
        const formData = new FormData()
        formData.append('chunk', chunk)
        formData.append('hash', fileHash)
        formData.append('filename', fileContainer.name)
        // console.log(`filename: ${fileContainer.name} - ${fileHash}`)
        return { formData, index }
      })
      .map(
        ({ formData, index }) =>
          fileService.uploadFileByFormData(
            formData,
            // 根据传入的切片返回不同的监听函数,在原先的前端上传逻辑中新增监听函数部分
            createProgressHandler(fileContainer.data[index]),
          ),

        // 原生请求：
        //   request({
        //   url: 'http://localhost:3001',
        //   data: formData
        // })
      )

    // 1. 并发请求,上传分片
    await Promise.all(requestList)

    // 2. 合并切片
    await mergeFileChunks()
  }

  /**
   * 监听函数更新 data 数组对应元素的 percentage 属性
   */
  const createProgressHandler = function (item: fileUpload) {
    return (progressEvent: any) => {
      item.percentage = parseInt(
        String((progressEvent.loaded / progressEvent.total) * 100),
      )
      console.log(`分片文件上传进度 ：${item.fileHash} - ${item.percentage} %`)
    }
  }

  /**
   * 合并切片
   */
  const mergeFileChunks = async function () {
    await fileService.mergeFileChunks({
      filename: fileContainer.name,
      size: chunkSize.value,
    })
  }

  /**
   * 生成文件hash(web-worker)
   * @param fileChunkList 文件分片
   */
  const calculateHash = function (fileChunkList: Array<{ file: Blob }>) {
    return new Promise((resolve) => {
      // 添加 worker 属性
      fileContainer.worker = new Worker('/hash.js')
      fileContainer.worker.postMessage({ fileChunkList })
      fileContainer.worker.onmessage = (e) => {
        const { percentage, hash } = e.data
        hashPercentage.value = percentage
        if (hash) {
          resolve(hash)
        }
      }
    })
  }

  /**
   * 重置上传文件
   */
  const resetFile = function () {
    initFileContainer()
    console.log('fileContainer', fileContainer)
    console.log('==================重置文件上传成功===============')
  }

  /**
   * 发起请求
   */
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const request = function ({
    url = '',
    method = 'post',
    data = {} as any,
    headers = {} as any,
  }) {
    return new Promise((resolve) => {
      const xhr = new XMLHttpRequest()
      xhr.open(method, url)
      Object.keys(headers).forEach((key) =>
        xhr.setRequestHeader(key, headers[key]),
      )
      xhr.send(data)
      xhr.onload = (e) => {
        resolve({
          data: (e.target as any).response,
        })
      }
    })
  }

  return {
    uploadFileInput,
    fileContainer,
    chunkSize,
    hashPercentage,
    calculateHash,
    resetFile,
    handleFileChange,
    handleUpload,
    mergeFileChunks,
  }
}
